using System;
using System.Collections.Generic;
using System.Text;
using GraphConstructor;
using PhoneNetwork.AntColony;

namespace PhoneNetwork
{
    public class PhoneCall
    {
        #region properties

        // the maximum length of the call
        public int Duration;
        // unique identifier
        public int CallID;
        // the starting node of the call
        public Node SourceNode;
        // the final desitination of the call
        public Node DestinationNode;
        // the current node the call is on
        public Node CurrentNode;
        // an array of all visited node ids
        public List<Node> VisitedNodes = new List<Node>();
        // an array of final visted arrays after xxxx
        public List<Node> FinalVisitedNodes = new List<Node>();
        // has the call finished
        public bool Finished = false;
        // has the call failed
        public bool HasFailed = false;
        // which direction is the ant agent moving in
        public AntDirection AntDirection;
        // the new value of the node
        public double NewValue = -1;
        // the final count for visited nodes
        public int finalVisitedNodeCount = 0;
        // total wait time for the call
        public int waitTime = 0;
        // if the call was successful
        public bool Successful = false;

        private static Random _durationRand;
        private static int _callID = 0;

        // create a new call with a source and destination node
        public PhoneCall(Node src, Node dest)
        {
            this.CallID = _callID++;
            this.SourceNode = src;
            this.DestinationNode = dest;
            this.CurrentNode = src;
            this.VisitedNodes.Add(this.SourceNode);
            this.Duration = GetRandomCallDuration();
        }

        #endregion

        // terminates the call and releases all network resources
        public void TerminateCall()
        {
            for (int i = 0; i < (CurrentNode.Data as Phone).Calls.Count; )
                if ((CurrentNode.Data as Phone).Calls[i] == this)
                    (CurrentNode.Data as Phone).Calls.RemoveAt(i);
                else
                    i++;
        }

        // this method is called before the ant agent moves in reverse.
        // any loops in the path will be removed to optimise routing
        public void LoopRemoval()
        {
            Node id1, id2;

            // loop through all the nodes to find multiple occurances
            // of the same path.
            for (int i = 0; i < VisitedNodes.Count; i++)
            {
                id1 = VisitedNodes[i];

                for (int j = i + 1; j < VisitedNodes.Count - 1; j++)
                {
                    id2 = VisitedNodes[j];

                    // if a loop has been found
                    if (id1 == id2)
                    {
                        // create a tempory arraylist
                        List<Node> tArray = new List<Node>();

                        for (int k = 0; k < VisitedNodes.Count - 1; k++)
                        {
                            //if(k>-1 && k)
                            tArray.Add(VisitedNodes[k]);
                        }

                        VisitedNodes = tArray;

                        //reset the outer loop indexer
                        i = 0;
                    }
                }
            }
        }

        // Gets the next Node to travel to
        public Edge ConnectNextNode()
        {
            // loop to determine if a direct connection is possible
            foreach (Edge e in CurrentNode.Adj)
            {
                // if the destination node is directly connected
                if (e.NodeTo == this.DestinationNode)
                    return e;
            }

            PheromoneTable table = (CurrentNode.Data as Phone).PheromoneTables[DestinationNode];
            Node Next = table.ProbablePath(VisitedNodes);
            foreach (Edge e in CurrentNode.Adj)
                if (e.NodeTo == Next)
                    return e;

            // TODO: Remove this
            // if all nodes are busy retun -1 and inform to wait
            return null;
        }
        /// <summary>
        /// Gets a random call duration
        /// </summary>
        /// <returns>Number of minutes</returns>
        public static int GetRandomCallDuration()
        {
            if (_durationRand == null)
                _durationRand = new Random(Environment.TickCount);
            return _durationRand.Next(1, 60);
        }
    }
}
